﻿using System;

namespace MLSharp.Clustering
{
	/// <summary>
	/// Wrapper class that fully implements the Knowledge Frontier
	/// Discovery process using COBWEB.
	/// </summary>
	public class CobwebKnowledgeFrontierDiscovery
	{
		#region Public Properties

		/// <summary>
		/// The cluster tree created by <see cref="DiscoverKnowledgeFrontiers"/>.
		/// </summary>
		public Cobweb Cobweb { get; private set; }

		/// <summary>
		/// The knowledge frontiers discovered by <see cref="DiscoverKnowledgeFrontiers"/>.
		/// </summary>
		public IKnowledgeFrontier[] KnowledgeFrontiers { get; private set; }

		/// <summary>
		/// The Cutoff passed to Cobweb, leave set to the default to use the default
		/// Cutoff defined by <see cref="Clustering.Cobweb"/>.
		/// </summary>
		public double Cutoff { get; set; }

		/// <summary>
		/// The Acuity passed to Cobweb, leave set to the default to use the default
		/// Acuity defined by <see cref="Clustering.Cobweb"/>.
		/// </summary>
		public double Acuity { get; set; }

		/// <summary>
		/// The Alpha passed to <see cref="KnowledgeFrontierDiscovery"/>, leave set to the default to use the default
		/// Alpha defined by <see cref="KnowledgeFrontierDiscovery"/>.
		/// </summary>
		public double Alpha { get; set; }

		/// <summary>
		/// The root node of the cluster tree.
		/// </summary>
		public IClusterNode RootNode
		{
			get 
			{
				if (Cobweb == null)
				{
					throw new InvalidOperationException("You must call DiscoverKnowledgeFrontiers first!");
				}

				return Cobweb.Root;
			}
		}

		#endregion

		#region Public Constructors

		/// <summary>
		/// Initializes all properties to their defaults.
		/// </summary>
		public CobwebKnowledgeFrontierDiscovery()
		{
			Alpha = Acuity = Cutoff = double.NaN;
		}

		#endregion

		#region Public Methods

		/// <summary>
		/// Builds a cluster tree using <see cref="Cobweb"/>, then discovers
		/// knowledge frontiers using <see cref="KnowledgeFrontierDiscovery"/>.
		/// </summary>
		/// <param name="dataSet"></param>
		public void DiscoverKnowledgeFrontiers(IDataSet dataSet)
		{
			Cobweb = new Cobweb();
			if (!double.IsNaN(Cutoff))
			{
				Cobweb.Cutoff = Cutoff;
			}
			if (!double.IsNaN(Acuity))
			{
				Cobweb.Acuity = Acuity;
			}
			Cobweb.BuildClusterTree(dataSet);

			KnowledgeFrontierDiscovery kfd = new KnowledgeFrontierDiscovery();
			if (!double.IsNaN(Alpha))
			{
				kfd.Alpha = Alpha;
			}
			KnowledgeFrontiers = kfd.FindFrontiers(Cobweb.Root, dataSet);
		}

		#endregion
	}
}
